package com.mxf.example.config.auth;

import com.mxf.example.exception.BizException;
import com.mxf.example.security.JwtAuthenticationEntryPoint;
import com.mxf.example.security.JwtAuthorizationTokenFilter;
import com.mxf.example.security.JwtUserDetailsService;
import com.mxf.example.security.MyAccessDeniedHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;


@Configuration
@EnableWebSecurity// 这个注解必须加，开启Security
@EnableGlobalMethodSecurity(prePostEnabled = true)//保证post之前的注解可以使用
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Autowired
    JwtUserDetailsService jwtUserDetailsService;

    @Autowired
    JwtAuthorizationTokenFilter authenticationTokenFilter;
    @Autowired
    MyAccessDeniedHandler myAccessDeniedHandler;

    @Value("${url.pass}")
    String passurl;

    //先来这里认证一下
    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        //这个方法是主要进行验证的地方，其中jwtUserDetailsService代码待会会看，passwordEncoder(passwordEncoderBean())是密码的一种加密方式。
        auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoderBean());
    }

    //这个方法是我们配置拦截的地方
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        String[] passurls = passurl.split(",");
        http
                .exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint)//认证异常处理类
                .accessDeniedHandler(myAccessDeniedHandler)//授权异常处理类
                .and()//进行下一项配置，为了区分必须加入.and()
                .authorizeRequests()//这个后边配置那些路径有需要什么权限，比如我配置的那几个url都是permitAll(),及不需要权限就可以访问。值得一提的是antMatchers(HttpMethod.OPTIONS, "/**")，是为了方便后面写前后端分离的时候前端过来的第一次验证请求，这样做，会减少这种请求的时间和资源使用
                .antMatchers(passurls).permitAll()
                .antMatchers(HttpMethod.OPTIONS, "/**").anonymous()
                .anyRequest().authenticated()// 剩下所有的验证都需要验证
                .and()
                .csrf().disable() // 禁用 Spring Security 自带的跨域处理,是为了防止csdf攻击的，至于什么是csdf攻击，请自行百度。
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);// 定制我们自己的 session 策略：调整为让 Spring Security 不创建和使用 session
        http.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);//这行代码主要是用于JWT验证
    }

    @Bean
    public PasswordEncoder passwordEncoderBean() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }


}
